package dataManagement.action.manager;

import java.io.Serializable;
import dataImport.action.manager.EntityReaderManager;
import dataImport.exception.MissingReader;
import dataImport.model.Configuration;
import dataImport.model.CustomAction;
import dataImport.model.EmoteBeforeAction;
import dataImport.model.Object;
import dataImport.model.Place;
import dataImport.model.PredefinedAction;
import dataImport.model.Requirement;
import dataImport.model.State;
import dataImport.model.abstracts.AbstractEntity;
import dataManagement.action.helper.UserDataCommunication;
import dataManagement.action.manager.storage.Storage;
import dataManagement.exception.ActionCouldNotBeExecuted;


public class ActionManager implements Serializable {

	private static final long serialVersionUID = -5531654902507994359L;

	private ActionLibrary actionLibrary;

	private Storage actionStorage;

	private Storage stateStorage;

	private Storage objectStorage;

	private Storage placeStorage;

	public ActionManager(final EntityReaderManager entityReaderManager) throws MissingReader {
		this.actionLibrary = new ActionLibrary(entityReaderManager);
		this.actionStorage = new Storage();
		this.stateStorage = new Storage();
		this.objectStorage = new Storage();
		this.placeStorage = new Storage();

		this.fillStorages(entityReaderManager);
	}

	private final void fillStorages(final EntityReaderManager entityReaderManager) throws MissingReader {
		for (AbstractEntity abstractEntity : entityReaderManager.getConfigurationReader().getAbstractEntities()) {
			final Configuration configuration = (Configuration) abstractEntity;
			switch (configuration.getStaticConfiguration()) {
				case INITIALACTION:
					final CustomAction customAction = (CustomAction) configuration.getAbstractEntity();
					this.actionStorage.add(customAction.getCommand().getPattern());
					break;
				case INITIALOBJECT:
					final Object object = (Object) configuration.getAbstractEntity();
					this.objectStorage.add(object.getName());
					break;
				case INITIALPLACE:
					final Place place = (Place) configuration.getAbstractEntity();
					this.placeStorage.add(place.getName());
					break;
				case INITIALSTATE:
					final State state = (State) configuration.getAbstractEntity();
					this.stateStorage.add(state.getName());
					break;
			}
		}
	}

	public final void execute(final String action) throws ActionCouldNotBeExecuted {
		if (!this.actionStorage.contains(action)) {
			throw new ActionCouldNotBeExecuted(action);
		}

		for (Requirement requirement : this.actionLibrary.getRequirements(action)) {
			if (!this.meet(requirement)) {
				throw new ActionCouldNotBeExecuted(action);
			}
		}

		EmoteBeforeAction emoteBeforeAction = this.actionLibrary.getEmoteBefore(action);
		if (emoteBeforeAction != null) {
			this.executeEmotion(emoteBeforeAction);
		}

		for (PredefinedAction predefinedAction : this.actionLibrary.getPredefinedActions(action)) {
			this.execute(predefinedAction);
		}
	}

	protected final void executeEmotion(final EmoteBeforeAction emote) {
		UserDataCommunication.println(emote.getText());
	}

	protected final void execute(final PredefinedAction predefinedAction) {
		switch (predefinedAction.getStaticAction()) {
			case CREATEOBJECT:
				final String objectName1 = ((Object) predefinedAction.getAbstractEntity()).getName();
				this.objectStorage.add(objectName1);
				break;
			case DESTROYOBJECT:
				final String objectName2 = ((Object) predefinedAction.getAbstractEntity()).getName();
				this.objectStorage.remove(objectName2);
				break;
			case CREATESTATE:
				final String stateName1 = ((State) predefinedAction.getAbstractEntity()).getName();
				this.stateStorage.add(stateName1);
				break;
			case DESTROYSTATE:
				final String stateName2 = ((State) predefinedAction.getAbstractEntity()).getName();
				this.stateStorage.remove(stateName2);
				break;
			case ADDPLACE:
				final String placeName1 = ((Place) predefinedAction.getAbstractEntity()).getName();
				this.placeStorage.add(placeName1);
				break;
			case REMOVEPLACE:
				final String placeName2 = ((Place) predefinedAction.getAbstractEntity()).getName();
				this.placeStorage.remove(placeName2);
				break;
			case ACTIVATEACTION:
				final String actionName1 = ((CustomAction) predefinedAction.getAbstractEntity()).getCommand().getPattern();
				this.actionStorage.add(actionName1);
				break;
			case DEACTIVATEACTION:
				final String actionName2 = ((CustomAction) predefinedAction.getAbstractEntity()).getCommand().getPattern();
				this.actionStorage.remove(actionName2);
				break;
		}
	}

	protected final boolean meet(final Requirement requirement) {
		switch (requirement.getStaticRequirement()) {
			case REQUIREOBJECT:
				final String objectName = ((Object) requirement.getAbstractEntity()).getName();
				return this.objectStorage.contains(objectName);
			case REQUIREPLACE:
				final String placeName = ((Place) requirement.getAbstractEntity()).getName();
				return this.placeStorage.contains(placeName);
			case REQUIRESTATE:
				final String stateName = ((State) requirement.getAbstractEntity()).getName();
				return this.stateStorage.contains(stateName);
		}

		return false;
	}

	protected final ActionLibrary getActionLibrary() {
		return this.actionLibrary;
	}

	protected final Storage getActionStorage() {
		return this.actionStorage;
	}

	protected final Storage getStateStorage() {
		return this.stateStorage;
	}

	protected final Storage getObjectStorage() {
		return this.objectStorage;
	}

	protected final Storage getPlaceStorage() {
		return this.placeStorage;
	}
}
